﻿using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using YJKArchUtils.Utils;
using YJKRevitBase.TopologySuite;
using YJKRevitKernel.RevitTopologySuite;
using YJKRevitDimensionText.OneKeyPlanDim.LevelDim.Data;
using YJKRevitDimensionText.OneKeyPlanDim.Utility;

namespace YJKRevitDimensionText.OneKeyPlanDim.LevelDim
{
	public class RoofLevelDim
	{
		public List<RoofBase> LstRoofBase
		{
			get
			{
				return this.m_lstFoofBase;
			}
		}

		public List<Floor> LstFloor
		{
			get
			{
				return this.m_lstFloor;
			}
		}

		public RoofLevelDim(Autodesk.Revit.DB.Document doc)
		{
			this.m_doc = doc;
		}

		public void AddRoof(Element ele)
		{
			if (ele is RoofBase)
			{
				this.m_lstFoofBase.Add(ele as RoofBase);
				return;
			}
			if (ele is Floor)
			{
				this.m_lstFloor.Add(ele as Floor);
			}
		}

		private void CreateSlopingRoofLevelDim(DimData dimData)
		{
			List<XYZ> list = new List<XYZ>();
			foreach (PlanarFace planarFace in dimData.lstPlanarFaceSlopeRoof)
			{
				List<Curve> list2 = new List<Curve>();
				this.GetMaxHeightLevelPt(planarFace, out list2);
				foreach (Curve curve in list2)
				{
					XYZ ptCenter = (curve.GetEndPoint(0) + curve.GetEndPoint(1)) / 2.0;
					if (list.Find((XYZ n) => n.IsAlmostEqualTo(ptCenter)) == null)
					{
						list.Add(ptCenter);
					}
				}
			}
			foreach (XYZ dimPosition in list)
			{
				this.DimCreatorInPt(dimPosition);
			}
		}

		private void CreateHalfSlopeRoofLevelDim(DimData dimData)
		{
			foreach (PlanarFace planarFace in dimData.lstPlanarFaceHalfSlopeRoof)
			{
				List<SingleLevelDimDataInfo> list = new List<SingleLevelDimDataInfo>();
				CommonLayerFloor commonLayerFloor = new CommonLayerFloor(this.m_doc);
				commonLayerFloor.ComponentInSlopePlanarFace = planarFace;
				commonLayerFloor.CreateKeyComponent(ref list, new List<List<Curve>>
				{
					GeometryHelper.GetAllEdgeList(planarFace)
				});
				if (list.Count == 0)
				{
					SingleLevelDimDataInfo singleLevelDimDataInfo = this.CreateLevelDimInPlanarFace(planarFace);
					if (singleLevelDimDataInfo != null)
					{
						list.Add(singleLevelDimDataInfo);
					}
				}
				commonLayerFloor.SetDimPosition(list);
			}
		}

		private void CreateSaveTheRoofLevelDim(DimData dimData)
		{
			foreach (XYZ dimPosition in dimData.m_lstSaveTheRoof)
			{
				this.DimCreatorInPt(dimPosition);
			}
		}

		private void CreateFlatRoofLevelDim(DimData dimData)
		{
			foreach (KeyValuePair<string, List<PlanarFace>> keyValuePair in dimData.ClassificationFaltPlanarFaceByLevel())
			{
				List<PlanarFace> value = keyValuePair.Value;
				List<SingleLevelDimDataInfo> list = new List<SingleLevelDimDataInfo>();
				CommonLayerFloor commonLayerFloor = new CommonLayerFloor(this.m_doc);
				double dLevelVal = 0.0;
				if (double.TryParse(keyValuePair.Key, out dLevelVal))
				{
					commonLayerFloor.dLevelVal = dLevelVal;
					List<List<Curve>> list2 = new List<List<Curve>>();
					foreach (PlanarFace planarFace in value)
					{
						list2.Add(GeometryHelper.GetAllEdgeList(planarFace));
					}
					commonLayerFloor.CreateKeyComponent(ref list, list2);
					if (list.Count == 0)
					{
						SingleLevelDimDataInfo singleLevelDimDataInfo = this.CreateDimIfNoComponent(value);
						if (singleLevelDimDataInfo != null)
						{
							list.Add(singleLevelDimDataInfo);
						}
					}
					commonLayerFloor.SetDimPosition(list);
				}
			}
		}

		private SingleLevelDimDataInfo CreateDimIfNoComponent(List<PlanarFace> lstPlanarFace)
		{
			double num = double.MinValue;
			PlanarFace lstPlanarFace2 = null;
			foreach (PlanarFace planarFace in lstPlanarFace)
			{
				if (Geometry.LessThan(num, planarFace.Area))
				{
					num = planarFace.Area;
					lstPlanarFace2 = planarFace;
				}
			}
			return this.CreateLevelDimInPlanarFace(lstPlanarFace2);
		}

		private SingleLevelDimDataInfo CreateLevelDimInPlanarFace(PlanarFace lstPlanarFace)
		{
			SingleLevelDimDataInfo singleLevelDimDataInfo = null;
			if (null != lstPlanarFace)
			{
				XYZ xyz = GeometryHelper.GeometricCenterOfPlanarFace(lstPlanarFace);
				FamilyInstance familyInstance = new LevelDimData(this.m_doc)
				{
					PtDimLocation = xyz,
					DimVal = (Common.FeetToMM(xyz.Z) / 1000.0).ToString("f3")
				}.CreateLevelDim();
				if (familyInstance == null)
				{
					return singleLevelDimDataInfo;
				}
				CurveLoop levelDimCurveLoop = OcclusionArea.GetLevelDimCurveLoop(this.m_doc, familyInstance);
				OcclusionArea.GetInstance().m_lstLevelDimCvLoop.Add(levelDimCurveLoop);
				AnnotationSymbol annotationSymbol = familyInstance as AnnotationSymbol;
				if (annotationSymbol == null)
				{
					return singleLevelDimDataInfo;
				}
				singleLevelDimDataInfo = new SingleLevelDimDataInfo(annotationSymbol);
				singleLevelDimDataInfo.LevelVal = xyz.Z;
				singleLevelDimDataInfo.PtLocation = xyz;
				singleLevelDimDataInfo.bStepDownDim = false;
			}
			return singleLevelDimDataInfo;
		}

		public void CreateLevelDim()
		{
			List<Element> list = new List<Element>();
			list.AddRange(this.m_lstFoofBase);
			list.AddRange(this.m_lstFloor);
			DimData dimData = this.RoofingClassification(list);
			this.CreateSaveTheRoofLevelDim(dimData);
			this.CreateFlatRoofLevelDim(dimData);
			this.CreateHalfSlopeRoofLevelDim(dimData);
			this.CreateSlopingRoofLevelDim(dimData);
		}

		private DimData RoofingClassification(List<Element> lstElement)
		{
			DimData dimData = new DimData();
			Transaction transaction = new Transaction(this.m_doc, "CopyRoofElement");
			try
			{
				transaction.Start();
				double num = 0.10122909661567112;
				foreach (Element element in lstElement)
				{
					double num2 = CommonInterface.CoreUpThickness(element);
					XYZ xyz = -XYZ.BasisZ * num2;
					ElementTransformUtils.MoveElement(this.m_doc, element.Id, xyz);
					List<PlanarFace> list = new List<PlanarFace>();
					List<PlanarFace> list2 = new List<PlanarFace>();
					List<PlanarFace> list3 = new List<PlanarFace>();
					List<PlanarFace> allPlanarFace = GeometryHelper.GetAllPlanarFace(element);
					if (allPlanarFace != null && allPlanarFace.Count >= 1)
					{
						List<PlanarFace> list4 = new List<PlanarFace>();
						foreach (PlanarFace planarFace in allPlanarFace)
						{
							if (!Geometry.Lessthan_Or_Equal(planarFace.FaceNormal.Z, 0.0) && this.IsUpPlanarFace(allPlanarFace, planarFace))
							{
								if (Geometry.IsEqual(planarFace.FaceNormal.AngleTo(XYZ.BasisZ), 0.0))
								{
									list.Add(planarFace);
								}
								else
								{
									list4.Add(planarFace);
								}
							}
						}
						this.DelContainPlanarFace(list4);
						foreach (PlanarFace planarFace2 in list4)
						{
							double num3 = planarFace2.FaceNormal.AngleTo(XYZ.BasisZ);
							if (Geometry.LessThan(Math.PI*.5, num3))
							{
								num3 = Math.PI - num3;
							}
							double num4 = 1.0 / Math.Tan(num3);
							if (Geometry.LessThan(num, num4))
							{
								list2.Add(planarFace2);
							}
							else
							{
								list3.Add(planarFace2);
							}
						}
						if (list.Count == 0 && list3.Count == 0)
						{
							XYZ zero = XYZ.Zero;
							if (this.IsSaveTheRoof(list2, out zero))
							{
								dimData.m_lstSaveTheRoof.Add(zero);
								continue;
							}
						}
						dimData.lstPlanarFaceFlatRoof.AddRange(list);
						dimData.lstPlanarFaceSlopeRoof.AddRange(list2);
						dimData.lstPlanarFaceHalfSlopeRoof.AddRange(list3);
					}
				}
				transaction.RollBack();
			}
			catch
			{
				transaction.RollBack();
			}
			return dimData;
		}

		private void DelContainPlanarFace(List<PlanarFace> lstPlanarFaceSlope)
		{
			RevitPolygonRelateOperater revitPolygonRelateOperater = new RevitPolygonRelateOperater();
			for (int i = 0; i < lstPlanarFaceSlope.Count; i++)
			{
				List<Curve> allEdgeList = GeometryHelper.GetAllEdgeList(lstPlanarFaceSlope[i]);
				RevitPolygonDataBean revitPolygonDataBeanMax = this.GetRevitPolygonDataBeanMax(allEdgeList);
				if (revitPolygonDataBeanMax == null)
				{
					lstPlanarFaceSlope.RemoveAt(i);
					i--;
				}
				else
				{
					for (int j = i + 1; j < lstPlanarFaceSlope.Count; j++)
					{
						List<Curve> allEdgeList2 = GeometryHelper.GetAllEdgeList(lstPlanarFaceSlope[j]);
						RevitPolygonDataBean revitPolygonDataBeanMax2 = this.GetRevitPolygonDataBeanMax(allEdgeList2);
						TopologyRelateKindEnum topologyRelateKindEnum;
						if (revitPolygonDataBeanMax2 == null)
						{
							lstPlanarFaceSlope.RemoveAt(j);
							j--;
						}
                        else if (revitPolygonRelateOperater.TryGetPolygonRelate(revitPolygonDataBeanMax, revitPolygonDataBeanMax2, out topologyRelateKindEnum))
						{
                            if (7 == (int)topologyRelateKindEnum || topologyRelateKindEnum == null)
							{
								lstPlanarFaceSlope.RemoveAt(j);
								j--;
							}
                            else if (5 == (int)topologyRelateKindEnum)
							{
								lstPlanarFaceSlope.RemoveAt(i);
								i--;
								break;
							}
						}
					}
				}
			}
		}

		private RevitPolygonDataBean GetRevitPolygonDataBeanMax(List<Curve> lstCv)
		{
			RevitPolygonDataBean result = null;
			List<CurveLoop> list = CommonInterface.CreateLoopsByCurves(KeyComponent.GetInstance().m_doc, lstCv);
			double num = double.MinValue;
			foreach (CurveLoop curveLoop in list)
			{
				try
				{
					RevitPolygonDataBean revitPolygonDataBean = new RevitPolygonDataBean(curveLoop, null, 3);
					if (revitPolygonDataBean != null && Geometry.LessThan(num, revitPolygonDataBean.Area.Value))
					{
						num = revitPolygonDataBean.Area.Value;
						result = revitPolygonDataBean;
					}
				}
				catch
				{
				}
			}
			return result;
		}

		private bool IsSaveTheRoof(List<PlanarFace> lstPlanarFaceSlopeRoof, out XYZ ptMaxLevelPt)
		{
			ptMaxLevelPt = XYZ.Zero;
			if (lstPlanarFaceSlopeRoof.Count < 3)
			{
				return false;
			}
			List<Curve> list = new List<Curve>();
			ptMaxLevelPt = this.GetMaxHeightLevelPt(lstPlanarFaceSlopeRoof[0], out list);
			for (int i = 1; i < lstPlanarFaceSlopeRoof.Count; i++)
			{
				if (!ptMaxLevelPt.IsAlmostEqualTo(this.GetMaxHeightLevelPt(lstPlanarFaceSlopeRoof[i], out list)))
				{
					return false;
				}
			}
			return true;
		}

		private XYZ GetMaxHeightLevelPt(PlanarFace planarFace, out List<Curve> lstCv)
		{
			lstCv = new List<Curve>();
			List<Curve> allEdgeList = GeometryHelper.GetAllEdgeList(planarFace);
			XYZ result = XYZ.BasisX;
			double num = double.MinValue;
			foreach (Curve curve in allEdgeList)
			{
				XYZ xyz = Geometry.LessThan(curve.GetEndPoint(0).Z, curve.GetEndPoint(1).Z) ? curve.GetEndPoint(1) : curve.GetEndPoint(0);
				if (Geometry.LessThan(num, xyz.Z))
				{
					lstCv.Clear();
					lstCv.Add(curve);
					num = xyz.Z;
					result = xyz;
				}
				else if (Geometry.IsEqual(num, xyz.Z))
				{
					lstCv.Add(curve);
				}
			}
			return result;
		}

		private void DimCreatorInPt(XYZ dimPosition)
		{
			FamilyInstance familyInstance = new LevelDimData(this.m_doc)
			{
				PtDimLocation = dimPosition,
				DimVal = (Common.FeetToMM(dimPosition.Z) / 1000.0).ToString("f3") + "（结）"
			}.CreateLevelDim();
			AnnotationSymbol annotationSymbol = null;
			if (familyInstance != null)
			{
				annotationSymbol = (familyInstance as AnnotationSymbol);
			}
			if (annotationSymbol != null)
			{
				CurveLoop levelDimCurveLoop = OcclusionArea.GetLevelDimCurveLoop(this.m_doc, annotationSymbol);
				OcclusionArea.GetInstance().m_lstLevelDimCvLoop.Add(levelDimCurveLoop);
				KeyComponent.GetInstance().m_lstLevelDimension.Add(annotationSymbol);
			}
		}

		private bool IsUpPlanarFace(List<PlanarFace> lstPlanarFace, PlanarFace planarFace)
		{
			XYZ xyz = CommonInterface.PtInPlanarFaceInDir(GeometryHelper.GeometricCenterOfPlanarFace(planarFace), planarFace, XYZ.BasisZ) + XYZ.BasisZ * Common.MMToFeet(20.0);
			XYZ xyz2 = xyz + XYZ.BasisZ * Common.MMToFeet(10000.0);
			Line line = Line.CreateBound(xyz, xyz2);
			foreach (Face face in lstPlanarFace)
			{
				IntersectionResultArray intersectionResultArray = null;
				face.Intersect(line, out intersectionResultArray);
				if (intersectionResultArray != null && !intersectionResultArray.IsEmpty)
				{
					return false;
				}
			}
			return true;
		}

		private List<RoofBase> m_lstFoofBase = new List<RoofBase>();

		private List<Floor> m_lstFloor = new List<Floor>();

		private Document m_doc;
	}
}
